package org.transmit;

import java.awt.font.NumericShaper;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.db.createdao.BaseDao;
import org.db.createdao.DatabaseUser;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.transmit.key.Business;
import org.transmit.key.Action;
import org.transmit.key.Parameters;
import org.transmit.key.Results;
import org.transmit.key.ReturnJSON;
import org.transmit.key.ReturnText;
import org.transmit.util.ActionPo;
import org.transmit.util.FileUtil;
import org.transmit.util.prdException;

/**
 * 系统启动时需要运行的方法
* @Title: StartUtil.java 
* @Package org.transmit.util 
* @Description: TODO 
* @author porridge
* @url  http://www.prdblog.com/
* @email  mfkwfc@gmail.com   
* @date 2014年4月12日 下午8:14:03 
* @version V1.0
 */
public class StartUtil {
	/**
	 * 启动读取配置
	 */
	protected static Map<String,String> configMap=new HashMap<String, String>();
	/**
	 * 存放扫包的成果,有那些符合要求的类
	 */
	private List<String> packurl=new ArrayList<String>();
	private static Logger log = Logger.getLogger(StartUtil.class);
	protected static Map<String,ActionPo> acts=new HashMap<String,ActionPo>();
	
	protected static DatabaseUser configdao;//数据库配置参数
	
	protected void init(){
		try{
			setConfigXML();//读配置
		}catch(Exception e){
			log.error("读取配置文件出现错误");
			e.printStackTrace();
		}
		sweepPackageFile(configMap.get("ActionUrl").split("\\."),FileUtil.URL,1);//一级过滤.得到符合要求的Action
		try {
			sweepPackClass();
			if("true".equals(configMap.get("showOnlineAction"))){
				log.info(FileUtil.URL+"prdConfiguration.xml");
				log.info(FileUtil.URL+configMap.get("ActionUrl").replace(".","\\"));
				for(String key:acts.keySet())
					log.info(key);
					
			}
		}catch(Exception e) {
			e.printStackTrace();
		}//二级过滤
	}
	/**
	 * 二级过滤,从符合要求中的Action得到详细信息并且保存
	 * @throws ClassNotFoundException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	private void sweepPackClass() throws InstantiationException, IllegalAccessException, ClassNotFoundException{
		ActionPo actpo=null;
		for(String url:packurl){
			Object obj=Class.forName(url).newInstance();
			
			String ActionUrl=url.substring(url.lastIndexOf(".")+1,url.lastIndexOf("Action")).toLowerCase()+"_";//访问地址去掉Action转小写
			
			if(obj.getClass().isAnnotationPresent(Action.class)){//检测访问地址 是否有指定
				Action name=obj.getClass().getAnnotation(Action.class);
				ActionUrl="/"+name.value()+"/"+ActionUrl;
			}
			
			//全局返回地址
			Map<String,String> parmap=new HashMap<String, String>();
			
			if(obj.getClass().isAnnotationPresent(Results.class)){//检测全局返回地址
				Results resus=obj.getClass().getAnnotation(Results.class);
				Parameters[] pars=resus.value();
				for(Parameters p:pars){
					parmap.put(p.name(),p.location());
				}
			}
			Method[] mets=obj.getClass().getDeclaredMethods();
			for(Method m:mets){
				if(acts.get(ActionUrl+m.getName())==null){
					actpo=new ActionPo();
					actpo.setPack(url);//存放父级包地址
					actpo.setParmap(parmap);//存放父级返回地址
					actpo.setMethod(m.getName());//存放方法
					actpo.setRettype(m.getReturnType().getName());
					if(m.isAnnotationPresent(ReturnJSON.class)){
						actpo.setConvertType("ReturnJSON");
					}
					if(m.isAnnotationPresent(ReturnText.class)){
						actpo.setConvertType("ReturnText");
					}
					acts.put(ActionUrl+m.getName(),actpo);
				}else{
					new prdException(ActionUrl+m.getName()+"出现重复地址");
				}
			}
		}
	}
	/**
	 * 扫包,扫出Action,  同理.哈哈.骚包
	 * 第一层过滤  找到所有的符合要求的Action
	 * @param urls  扫包集合
	 * @param tier  层级
	 */
	private void sweepPackageFile(String[] urls,String parurl,int tier){
		String url="";
		boolean bl=false;
		if(urls.length>tier){
			for(int i=0;i<=tier;i++){
				if(!"*".equals(urls[i]))
					url+=urls[i]+File.separator;
				else{
					if(!parurl.equals(FileUtil.URL)){
						File tfile=new File(parurl);
						url+=tfile.getName()+File.separator;
						parurl=FileUtil.URL;
					}
				}
			}
			bl=true;
		}
		if(urls.length==1 && "*".equals(urls[0]))
			bl=true;
		
		if("true".equals(configMap.get("showOnlineAction")))
			log.info("扫包地址:"+parurl+url);
		
		if(bl){
			File file=new File(parurl+url);
			if(file.exists()){
				File[] fs=file.listFiles();
				for(File f:fs){
					if(f.isFile()){//文件时处理方法
						String fe=f.getPath();
						if(fe.lastIndexOf(".")!=-1){
							fe=fe.substring(0,fe.lastIndexOf("."));
							if(fe.indexOf("Action")+6==fe.length()){
								//必须以File.separator 替换 win or linux 路径计算方式不同
								packurl.add(fe.substring(FileUtil.URL.length(),fe.length()).replace(File.separator,"."));
							}
						}
					}else{
						sweepPackageFile(urls,f.getPath(),tier+1);
					}
				}
			}
		}
		
	}
	/**
	 * 处理配置信息
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 */
	private void setConfigXML() throws Exception{
		String url=FileUtil.URL;
		url+="prdConfiguration.xml";
		File file=new File(url);
		if(file.exists() && file.isFile()){
			try {
				SAXReader reader = new SAXReader();
				Document document;
				document = reader.read(file);
				Element rootElement = document.getRootElement();
				Iterator i = rootElement.elementIterator();
				for (;i.hasNext();) {
					Element element = (Element) i.next();
					if("database".equals(element.getName())){
						Iterator i1 = element.elementIterator();
						DatabaseUser data=new DatabaseUser();
						for(;i1.hasNext();){
							Element element1=(Element)i1.next();
							Field fld=data.getClass().getDeclaredField(element1.getName());
							if(fld!=null){
								fld.setAccessible(true);
								if(String.class==fld.getType())
									fld.set(data,element1.getText());
								else if("int".equals(fld.getType().toString())){
									if(element1.getText()!=null && element1.getText().trim().length()>0 && element1.getText().trim().matches("\\d*"))
										fld.set(data,Integer.valueOf(element1.getText().trim()));
								}
							}
						}
						if(configdao==null)
							configdao=data;
					}else
						configMap.put(element.getName(),element.getText().trim());
				}
			} catch (DocumentException e) {
				e.printStackTrace();
			}
		}else{
			log.error("配置文件不存在.......");
		}
		//如果没有配置则默认
		if(configMap.get("requestCoding")==null){
			configMap.put("requestCoding","UTF-8");
		}
		if(configMap.get("responseCoding")==null){
			configMap.put("responseCoding","UTF-8");
		}
		if(configMap.get("ActionUrl")==null){
			configMap.put("ActionUrl","*");
		}
	}
	/**
	 * 设置他们的编码
	 * @param reqs
	 * @param resp
	 */
	protected static void setEncodingAndLocale(HttpServletRequest reqs,HttpServletResponse resp){
		String encoding=configMap.get("requestCoding");
		try {
	            if (!encoding.equals(reqs.getCharacterEncoding())) {
	            	reqs.setCharacterEncoding(encoding);
	            }
	            resp.setCharacterEncoding(configMap.get("responseCoding"));
	        } catch (Exception e) {
	        	System.out.println("设置"+encoding+"编码错误");
	        	e.printStackTrace();
	        }
	}
	/**
	 * 寻址.转发请求
	 * @param actpo
	 */
	protected static void transmitAction(ActionPo actpo){
			Object obj=null;
			try {
				obj = Class.forName(actpo.getPack()).newInstance();
			} catch (InstantiationException e1) {
				e1.printStackTrace();
			} catch (IllegalAccessException e1) {
				e1.printStackTrace();
			} catch (ClassNotFoundException e1) {
				e1.printStackTrace();
			}
			/**
			 * 检查是否有@business  如果有则实例化该功能
			 */
			Field[] fls=obj.getClass().getDeclaredFields();
			setActionVariable(fls,obj);//映射变量进去
			boolean isopencon=false;//判断action 是否有business有则开启数据库连接
			boolean isrollback=false;//判断是否需要回滚数据
			for(Field f:fls){
				f.setAccessible(true);
				if(f.isAnnotationPresent(Business.class)){
						try {
							//先开启数据库存,再实例化business
							if(!isopencon)
								ThreadDao.setDaoPo(BaseDao.dao.getCon());//开启数据库连接
							f.set(obj,Class.forName(f.getType().getName()).newInstance());
							isopencon=true;//只开启一次事务，每次请求BUSSINESS都共用一个事务。保证数据的完整性
						} catch (IllegalArgumentException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (InstantiationException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (ClassNotFoundException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
				}
			}
			
			Object retobj=null;
			try {
				retobj = obj.getClass().getDeclaredMethod(actpo.getMethod(),null).invoke(obj);//正式调用该方法
				isrollback=true;
			} catch (IllegalAccessException e1) {
				e1.printStackTrace();
			} catch (IllegalArgumentException e1) {
				e1.printStackTrace();
			} catch (InvocationTargetException e1) {
				e1.printStackTrace();
			} catch (NoSuchMethodException e1) {
				e1.printStackTrace();
			} catch (SecurityException e1) {
				e1.printStackTrace();
			}finally{
				if(isopencon){
					if(isrollback){//如果正常运行则提交.不正常运行则回滚数据
						ThreadDao.commit();
					}else{
						ThreadDao.rollback();
					}
					ThreadDao.closedao();//关闭数据库连接
				}
			}
			if(retobj!=null){
				if(!"void".equals(actpo.getRettype()) && retobj!=null && !"null".equals(retobj)){
					if(String.class.getName().equals(actpo.getRettype())){
						if("ReturnText".equals(actpo.getConvertType())){//原样输出String
							ActionContext.getPrintWriter().print(retobj);
						}else{//跳转页面
							String path=actpo.getParmap().get(retobj.toString());
							if(path!=null && path.trim().length()>0)
								ActionContext.gotoPath(path);
							else{
								new prdException("未找到"+retobj.toString()+"跳转地址");
							}
						}
					}
					if("ReturnJSON".equals(actpo.getConvertType())){
							String retjson=null;
							try{
								retjson=JSONArray.fromObject(retobj).toString();
							}catch(Exception e){
								log.error("json 引用包加载不全或者转换发生错误...");
								e.printStackTrace();
							}
							if(retjson!=null)
								ActionContext.getPrintWriter().print(retjson);
					}
				}
			}
	}
	/**
	 * 映射变量进入Action
	 * 目前只支持  String int float double boolean  以及实体绑定  六种方式
	 */
	protected static void setActionVariable(Field[] fls,Object obj){
		HttpServletRequest req=ActionContext.getRequest();
		Map params =req.getParameterMap();
		Object temp=null;
		for(Field f:fls){
			if(!f.isAnnotationPresent(Business.class)){//仅仅是普通变量时处理
				try {
					f.setAccessible(true);
					if(f.getType()==String.class){
						temp=req.getParameter(f.getName());
						if(temp!=null)
							f.set(obj,temp.toString().trim());
					}else if(f.getType()==Integer.class || "int".equals(f.getType().getName())){
						temp=req.getParameter(f.getName());
						if(temp!=null && temp.toString().trim().length()>0){
							if(temp.toString().trim().matches("\\d*")){
								f.set(obj,Integer.valueOf(temp.toString().trim()));
							}else{
								log.error(f.getName()+"转换数字失败   "+temp);
							}
						}
					}else if(f.getType()==Float.class || f.getType()==Double.class
							|| "double".equals(f.getType().getName()) || "float".equals(f.getType().getName())){
						temp=req.getParameter(f.getName());
						if(temp!=null && temp.toString().trim().length()>0){
							if(temp.toString().trim().matches("\\d*.\\d*")){
								f.set(obj,Integer.valueOf(temp.toString().trim()));
							}else{
								log.error(f.getName()+"转换浮点数失败   "+temp);
							}
						}
					}else if(f.getType()==Boolean.class || f.getType().getName().equals("boolean")){
						temp=req.getParameter(f.getName());
						if(temp!=null){
							if("true".equals(temp.toString()) || "1".equals(temp.toString()))
								f.set(obj,true);
							else
								f.set(obj,false);
						}
					}else if(f.getType()==File.class){
						if(ServletFileUpload.isMultipartContent(req)){
							System.out.println("暂时未实现上传文件...........");
						}
					}else{//处理对象  比如  stu.name  存放到student对象里边 用的是apache里边的自带方法  BeanUtils.populate
						Map<String,String[]> tmap=new HashMap<String,String[]>();
						Set<Map.Entry<String, String[]>> lv=params.entrySet();
						for(Map.Entry<String, String[]> l:lv){
							if(l.getKey().indexOf(f.getName()+".")==0){
								tmap.put(l.getKey().replace(f.getName()+".",""),l.getValue());
							}
						}
						Object temppo=Class.forName(f.getType().getName()).newInstance();
						BeanUtils.populate(temppo,tmap);
						f.set(obj,temppo);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * 传入key查询配置
	 * @param key
	 * @return
	 */
	public static String findConfig(String key){
		String ret=null;
		if(key!=null){
			ret=configMap.get(key);
		}
		return ret;
	}
	/**
	 * 返回数据库配置信息.
	 * 防止更改。所以复制一份对象给他操作
	 * @return
	 */
	public static DatabaseUser findDatabaseConfig(){
		return configdao.copy();
	}
	
	public static String getUUID(){
		return UUID.randomUUID().toString().replace("-","");
	}
}